package com.groupbuying.storeinternal.config;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * @anthor wenguoqiang
 * @date: 2019/01/16 16:03
 * @company
 * @des
 **/
@Configuration
public class HttpClientConfig {


        @Value("${httpclient.maxTotal}")
        private Integer maxTotal;

        @Value("${httpclient.defaultMaxPerRoute}")
        private Integer defaultMaxPerRoute;

        @Value("${httpclient.connectTimeout}")
        private Integer connectTimeout;

        @Value("${httpclient.connectionRequestTimeout}")
        private Integer connectionRequestTimeout;

        @Value("${httpclient.socketTimeout}")
        private Integer socketTimeout;

        @Value("${httpclient.staleConnectionCheckEnabled}")
        private boolean staleConnectionCheckEnabled;

        /**
         * 首先实例化一个连接池管理器，设置最大连接数、并发连接数
         * @return
         */
        @Bean(name = "httpClientConnectionManager")
        public PoolingHttpClientConnectionManager getHttpClientConnectionManager(){
           // PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager();
             //解决证书问题 时间 2019年2月22日18:15:39
            PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager(getRegistry());
            //最大连接数
            httpClientConnectionManager.setMaxTotal(maxTotal);
            //并发数
            httpClientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
            return httpClientConnectionManager;
        }

        public Registry getRegistry(){

            /**
             * 绕过https证书验证 避免握手失败
             */
            X509TrustManager tm = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] chain,
                                               String authType) throws CertificateException {
                }
                public void checkServerTrusted(X509Certificate[] chain,
                                               String authType) throws CertificateException {
                }
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            Registry<ConnectionSocketFactory> registry = null;
            try {
                SSLContext ctx = SSLContext.getInstance("TLS");
                ctx.init(null, new TrustManager[]{tm}, null);
                SSLSocketFactory ssf = new SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

                System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
                registry = RegistryBuilder.<ConnectionSocketFactory>create()
                        .register("https", ssf)
                        .register("http", PlainConnectionSocketFactory.getSocketFactory())
                        .build();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }
            return registry;
        }


        /**
         * 实例化连接池，设置连接池管理器。
         * 这里需要以参数形式注入上面实例化的连接池管理器
         * @param httpClientConnectionManager
         * @return
         */
        @Bean(name = "httpClientBuilder")
        public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager")PoolingHttpClientConnectionManager httpClientConnectionManager){

            //HttpClientBuilder中的构造方法被protected修饰，所以这里不能直接使用new来实例化一个HttpClientBuilder，可以使用HttpClientBuilder提供的静态方法create()来获取HttpClientBuilder对象
            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();

            httpClientBuilder.setConnectionManager(httpClientConnectionManager);

            return httpClientBuilder;
        }

        /**
         * 注入连接池，用于获取httpClient
         * @param httpClientBuilder
         * @return
         */
        @Bean
        public CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder){
            return httpClientBuilder.build();
        }

        /**
         * Builder是RequestConfig的一个内部类
         * 通过RequestConfig的custom方法来获取到一个Builder对象
         * 设置builder的连接信息
         * 这里还可以设置proxy，cookieSpec等属性。有需要的话可以在此设置
         * @return
         */
        @Bean(name = "builder")
        public RequestConfig.Builder getBuilder(){
            RequestConfig.Builder builder = RequestConfig.custom();
            return builder.setConnectTimeout(connectTimeout)
                    .setConnectionRequestTimeout(connectionRequestTimeout)
                    .setSocketTimeout(socketTimeout)
                    .setStaleConnectionCheckEnabled(staleConnectionCheckEnabled);
        }

        /**
         * 使用builder构建一个RequestConfig对象
         * @param builder
         * @return
         */
        @Bean
        public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder){
            return builder.build();
        }



}
